local m_3v3_desc = [[

# 3v3模式简介

  六名玩家3v3进行对战的竞技模式。

  若为“统帅三军”规则，则改为两名玩家1v1对战，每名玩家控制三名角色（统帅三军模式暂无）。

  3v3模式规则历年经过多次修改，新月杀采用的是2023版王者之战规则。

  ___

  ## 阵营分布

  分为暖色方、冷色方双方阵营，每阵营为一名“主帅”和两名“先锋”。暖色方身份牌为红色，冷色方身份牌为蓝色。

  座次固定为：冷方先锋A-冷方主帅-冷方先锋B-暖方先锋A-暖方主帅-暖方先锋B

  ___

  ## 胜利条件

  消灭敌方阵营的主帅。

  ___

  ## 选将流程

  游戏开始前，展示16张公共武将牌，由双方主帅为本方阵营挑选武将。

  由暖色方开始，按1-2-2-...-2-1的数量，双方交替选择武将。

  完成选将后，主帅为本方的三名角色选择武将，然后同时亮出，游戏开始。

  ___

  ## 初始体力与手牌

  主帅的初始体力上限和初始体力值+1，但不会获得主公技。

  暖色方主帅初始手牌数+1。

  ___

  ## 行动顺序

  行动顺序是3v3模式与其他游戏模式最大的区别。

  每轮游戏分为四个行动单元。每个行动单元中，主帅选择：1.自己行动；2.选择一名本方先锋，该先锋行动，然后另一名先锋行动。

  1. 由冷色方开始，执行一个行动单元；

  2. 然后暖色方执行一个行动单元；

  3. 冷色方执行剩余的一个行动单元（即：若第一个行动单元时选择主帅行动，则此时两名先锋行动；若第一个行动单元时选择两名先锋行动，则此时主帅行动）；

  4. 最后再由暖色方执行最后一个行动单元。

  5. 所有角色都行动后，完成一轮。

  线下模式中，会将身份牌横置以表示本轮已行动。在新月杀中，为行动的角色增加“已行动”标记（小红旗）以表示本轮已行动。

  ___

  ## 击杀奖惩

  击杀一名先锋角色后，摸两张牌。（贴吧早年梗：冷主收边）

  ___

  ## 特殊规则

  本模式AOE卡牌（【南蛮入侵】、【万箭齐发】、【桃园结义】、【五谷丰登】）在使用前，使用者选择按顺时针或逆时针方向进行结算。

  ___

  ## 游戏牌堆

  本模式采用特殊的精简后的标准版+军争牌堆，牌堆列表参见卡牌一览。

  注意，部分卡牌效果进行了修改：

  - 【无中生有】：出牌阶段，对你使用，目标角色摸两张牌。若己方角色数少于敌方角色数，则多摸一张牌。
  - 【诸葛连弩】替换为【连弩】：锁定技，你于出牌阶段内使用【杀】次数上限+3。
]]

local m_3v3_getLogic = function()
  local m_3v3_logic = GameLogic:subclass("m_3v3_logic")

  function m_3v3_logic:initialize(room)
    GameLogic.initialize(self, room)
    self.role_table = {
      { "cool_vanguard", "cool_marshal", "cool_vanguard", "warm_vanguard", "warm_marshal", "warm_vanguard" },
    }
  end

  function m_3v3_logic:assignRoles()
    local room = self.room
    local roles = self.role_table[math.random(1, 1)]
    table.shuffle(room.players)
    for i = 1, #room.players do
      local p = room.players[i]
      p.role = roles[i]
      room:setPlayerProperty(p, "role_shown", true)
      room:broadcastProperty(p, "role")
    end
    room:setCurrent(room.players[1])
  end

  function m_3v3_logic:chooseGenerals()
    local room = self.room
    math.randomseed(tonumber(tostring(os.time()):reverse():sub(1, 6)))

    local cool_marshal = room.players[2]
    local warm_marshal = room.players[5]
    room:setCurrent(cool_marshal)

    for _, name in ipairs(room.general_pile) do
      if not Fk:canUseGeneral(name) then
        table.removeOne(room.general_pile, name)
      end
    end

    table.shuffle(room.general_pile)
    local all_generals = room:getNGenerals(16)
    if #all_generals < 16 then
      room:sendLog {
        type = "#NoGeneralDraw",
        toast = true,
      }
      room:gameOver("")
    end

    local cool_generals, warm_generals = {}, {}
    local cool_selected, warm_selected = {}, {}

    local updataGeneralPile = function(p)
      if p == cool_marshal then
        room:setBanner("@&cool_generals", cool_generals)
      else
        room:setBanner("@&warm_generals", warm_generals)
      end
    end
    local function chooseGeneral(p, n)
      local prompt = "#3v3_mode-choose:::" .. (p == cool_marshal and "firstPlayer" or "secondPlayer") .. ":" .. n
      local my_selected = (p == cool_marshal) and cool_selected or warm_selected
      local ur_selected = (p == cool_marshal) and warm_selected or cool_selected
      local my_genrals = (p == cool_marshal) and cool_generals or warm_generals
      local result = room:askToCustomDialog(p, {
        skill_name = "m_3v3_mode",
        qml_path = "packages/gamemode_hy/qml/1v1.qml",
        extra_data = {
          all_generals, n, my_selected, ur_selected, prompt
        }
      })
      local selected = {}
      if result ~= "" then
        ---@cast result any
        for i, id in ipairs(result.ids) do
          local g = result.generals[i]
          -- 更新武将替换
          all_generals[id + 1] = g
          table.insert(my_selected, id)
          table.insert(my_genrals, g)
          table.insert(selected, g)
        end
      else
        local selected_list = table.connect(my_selected, ur_selected)
        for i, g in ipairs(all_generals) do
          if not table.contains(selected_list, i - 1) then
            table.insert(my_selected, i - 1)
            table.insert(my_genrals, g)
            table.insert(selected, g)
            if #selected == n then break end
          end
        end
      end
      room:sendLog {
        type = "#1v1ChooseGeneralsLog",
        arg = p == cool_marshal and "cool" or "warm",
        arg2 = selected[1],
        arg3 = selected[2] or "",
        toast = true,
      }
      updataGeneralPile(p)
    end

    chooseGeneral(warm_marshal, 1)
    chooseGeneral(cool_marshal, 2)
    chooseGeneral(warm_marshal, 2)
    chooseGeneral(cool_marshal, 2)
    chooseGeneral(warm_marshal, 2)
    chooseGeneral(cool_marshal, 2)
    chooseGeneral(warm_marshal, 2)
    chooseGeneral(cool_marshal, 2)
    chooseGeneral(warm_marshal, 1)

    local req = Request:new({cool_marshal, warm_marshal}, "AskForGeneral")
    req.timeout = self.room:getSettings('generalTimeout')
    req:setData(cool_marshal, { cool_generals, 3, true })
    req:setDefaultReply(cool_marshal, table.random(cool_generals, 3))
    req:setData(warm_marshal, { warm_generals, 3, true })
    req:setDefaultReply(warm_marshal, table.random(warm_generals, 3))

    room:doBroadcastNotify("ShowToast", Fk:translate("3v3_choose_general"), { cool_marshal, warm_marshal })
    req:ask()

    room:setBanner("@&cool_generals", 0)
    room:setBanner("@&warm_generals", 0)

    local generals = {}
    table.insertTable(generals, req:getResult(cool_marshal))
    table.insertTable(generals, req:getResult(warm_marshal))

    for i = 1, 6, 1 do
      local p = room.players[i]
      room:setPlayerGeneral(p, generals[i], true, true)
      room:broadcastProperty(p, "general")
    end
  end

  function m_3v3_logic:attachSkillToPlayers()
    local room = self.room
    local addRoleModSkills = function(player, skillName)
      local skill = Fk.skills[skillName]
      if not skill then
        fk.qCritical("Skill: " .. skillName .. " doesn't exist!")
        return
      end
      if skill:hasTag(Skill.Lord) then
        return
      end
      if skill:hasTag(Skill.AttachedKingdom) and not table.contains(skill:getSkeleton().attached_kingdom, player.kingdom) then
        return
      end

      room:handleAddLoseSkills(player, skillName, nil, false)
    end
    for _, p in ipairs(room.alive_players) do
      for _, s in ipairs(Fk.generals[p.general]:getSkillNameList(false)) do
        addRoleModSkills(p, s)
      end
      if p.deputyGeneral ~= "" then
        for _, s in ipairs(Fk.generals[p.deputyGeneral]:getSkillNameList(false)) do
          addRoleModSkills(p, s)
        end
      end
    end
  end

  ---@class m_3v3_Round: GameEvent.Round
  local m_3v3_Round = GameEvent.Round:subclass("m_3v3_Round")
  function m_3v3_Round:action()
    local room = self.room
    local cool_marshal = table.find(room.players, function(p)
      return p.role == "cool_marshal"
    end)
    local warm_marshal = table.find(room.players, function(p)
      return p.role == "warm_marshal"
    end)
    local function CommandAction(marshal)
      room = marshal.room
      local friends = table.filter(room.alive_players, function(p)
        return marshal:isFriend(p) and p:getMark("@!action-round") == 0
      end)
      if #friends > 0 then
        local to = friends[1]
        if #friends > 1 then
          to = room:askToChoosePlayers(marshal, {
            min_num = 1,
            max_num = 1,
            targets = friends,
            skill_name = "m_3v3_gamerule",
            prompt = "#m_3v3_action",
            cancelable = false,
          })[1]
        end
        room:setCurrent(to)
        room:setPlayerMark(to, "@!action-round", 1)
        GameEvent.Turn:create(TurnData:new(to)):exec()
        room:actExtraTurn()
        while to ~= marshal do
          if room.game_finished then break end
          local vanguards = table.filter(room.alive_players, function(p)
            return p.role:endsWith("vanguard") and marshal:isFriend(p) and p:getMark("@!action-round") == 0
          end)
          if #vanguards > 0 then
            to = vanguards[1]
            if #vanguards > 1 then
              to = room:askToChoosePlayers(marshal, {
                min_num = 1,
                max_num = 1,
                targets = vanguards,
                skill_name = "m_3v3_gamerule",
                prompt = "#m_3v3_action",
                cancelable = false,
              })[1]
            end
            room:setCurrent(to)
            room:setPlayerMark(to, "@!action-round", 1)
            GameEvent.Turn:create(TurnData:new(to)):exec()
            room:actExtraTurn()
          else
            break
          end
        end
      end
    end
    while table.find(room.alive_players, function(p)
        return p:getMark("@!action-round") == 0
      end) do
      if room.game_finished then break end
      CommandAction(cool_marshal)
      if room.game_finished then break end
      CommandAction(warm_marshal)
    end
  end

  function m_3v3_logic:action()
    local room = self.room
    self:trigger(fk.GamePrepared)

    GameEvent.DrawInitial:create():exec()

    while true do
      m_3v3_Round:create():exec()
      if room.game_finished then break end
    end
  end

  return m_3v3_logic
end

local m_3v3_mode = fk.CreateGameMode {
  name = "m_3v3_mode",
  minPlayer = 6,
  maxPlayer = 6,
  logic = m_3v3_getLogic,
  rule = "#m_3v3_rule&",
  surrender_func = function(self, playedTime)
    if Self.role:endsWith("vanguard") then
      return { { text = "vanguard_never_surrender", passed = false } }
    else
      local canSurrender = true
      if table.find(Fk:currentRoom().players, function(p)
            return (p.rest > 0 or not p.dead) and p ~= Self and Self:isFriend(p)
          end) then
        canSurrender = false
      end
      return { { text = "marshal_surrender", passed = canSurrender } }
    end
  end,
  whitelist = function(self, pkg)
    if pkg.type == Package.GeneralPack then
      return true
    elseif pkg.name == "3v3_cards" then
      return true
    end
  end,
  winner_getter = function(self, victim)
    if not victim.surrendered and victim.rest > 0 then
      return ""
    end
    if victim.role == "cool_marshal" then
      return "warm_marshal+warm_vanguard"
    elseif victim.role == "warm_marshal" then
      return "cool_marshal+cool_vanguard"
    end
    return ""
  end,
  get_adjusted = function(self, player)
    if player.role:endsWith("marshal") then
      return { hp = player.hp + 1, maxHp = player.maxHp + 1 }
    end
    return {}
  end,
  build_draw_pile = function(self)
    local draw, void = GameMode.buildDrawPile(self)
    local room = Fk:currentRoom()

    for i = #draw, 1, -1 do
      local id = draw[i]
      local card = Fk:getCardById(id)
      if card.name == "lightning" then
        table.remove(draw, i)
        table.insert(void, id)
      elseif card.name == "ex_nihilo" then
        table.insert(void, id)
        local newCard = AbstractRoom.printCard(room, "v33__ex_nihilo", card.suit, card.number)
        draw[i] = newCard.id
      elseif card.name == "crossbow" then
        table.insert(void, id)
        local newCard = AbstractRoom.printCard(room, "xbow", card.suit, card.number)
        draw[i] = newCard.id
      end
    end

    return draw, void
  end,
  reward_punish = function(self, victim, killer)
    if killer and victim.role:endsWith("vanguard") and not killer.dead then
      killer:drawCards(2, "kill")
    end
  end,
  friend_enemy_judge = function(self, targetOne, targetTwo)
    return targetOne.role[1] == targetTwo.role[1]
  end,
}

Fk:loadTranslationTable {
  ["m_3v3_mode"] = "3v3",
  [":m_3v3_mode"] = m_3v3_desc,
  ["cool"] = "冷色方",
  ["warm"] = "暖色方",
  ["cool_marshal"] = "冷方主帅",
  ["warm_marshal"] = "暖方主帅",
  ["cool_vanguard"] = "冷方先锋",
  ["warm_vanguard"] = "暖方先锋",

  ["#3v3_mode-choose"] = "你是[%arg]，请选择 %arg2 张武将牌作为备选",
  ["#3v3ChooseGeneralsLog"] = "%arg 选择了 %arg2 %arg3",
  ["3v3_choose_general"] = "请为本方阵营选择选择武将，从左至右为：左方先锋 主帅 右方先锋",
  ["@&cool_generals"] = "冷方已选武将",
  ["@&warm_generals"] = "暖方已选武将",

  ["m_3v3_gamerule"] = "选择",
  ["#m_3v3_action"] = "选择一名友方角色行动",

  ["#m_3v3_aoe-choice"] = "选择你使用%arg结算的方向",

  ["cool_marshal+cool_vanguard"] = "冷色方",
  ["warm_marshal+warm_vanguard"] = "暖色方",
  ["vanguard_never_surrender"] = "先锋永不投降！",
  ["marshal_surrender"] = "本阵营先锋均阵亡",


  ["m_1v1_mode"] = "1v1",
  ["#1v1ChooseGeneralsLog"] = "%arg 选择了 %arg2 %arg3",
  ["firstPlayer"] = "先手",
  ["secondPlayer"] = "后手",
  ["#1v1_mode-choose"] = "你是[%arg]，请选择 %arg2 张武将牌作为备选",
  ["1v1 choose general"] = "请选择第一名出战的武将",
  ["#1v1Score"] = "已阵亡武将数 先手 %arg : %arg2 后手",
  ["@firstFallen"] = "先手阵亡数",
  ["@secondFallen"] = "后手阵亡数",
  ["@&firstGenerals"] = "先手备选区",
  ["@&secondGenerals"] = "后手备选区",
  ["@&firstExiled"] = "先手流放区",
  ["@&secondExiled"] = "后手流放区",
}

return m_3v3_mode
